#include "StdAfx.h"
#include "Planet.h"
#include "player.h"
#include "gamescene.h"
#include "ships.h"
#include "FlightInfo.h"
#include "ShipsArrivedInfo.h"

const int JointPenWidth = 2;
const QColor jointPenColor = QColor(255,255,255);
const unsigned int percentOfShips = 50;
static const char* cosmosTexture = ":/galcon/Resources/images/cosmos_texture.png";
// Absolute distance that the wheel is rotated, in eighths (1/8s) of a degree. A positive value indicates 
// that the wheel was rotated forwards away from the user; a negative value indicates that the wheel was 
// rotated backwards toward the user.
// Most mouse types work in steps of 15 degrees, in which case the delta value is a multiple of 120 (== 15 * 8)
const int distanceInRotation = 120;
const int percentageAddend = 5;
bool playersEqual(PlanetID id1, PlanetID id2)
{
   return id1 == id2;
}

bool playersNotEqual(PlanetID id1, PlanetID id2)
{
   return !playersEqual(id1, id2);
}

GameScene::GameScene(PlanetsMapPtr planets, PlayersMapPtr players, PlayerID playerID, Distances distancesBtwPlanets, Angles anglesBtwPlanets,  QObject *parent)
   : QGraphicsScene(parent)
   , m_jointPen(jointPenColor)
   , m_currentItem(NULL)
   , m_planets(planets)
   , m_players(players)
   , m_playerID(playerID)
   , m_distances(distancesBtwPlanets)
   , m_angles(anglesBtwPlanets)
   , m_percentage(percentOfShips)
{
   init();
}

GameScene::~GameScene()
{
   qDebug() << "GameScene destructor";
   disconnectSignals();
}

void GameScene::init()
{
   m_jointPen.setWidth(JointPenWidth);
   QPixmap backgroundTexture(cosmosTexture);
   m_backgroundBrush = boost::make_shared<QBrush>(backgroundTexture);
   setBackgroundBrush(*m_backgroundBrush);
   m_percentageText = boost::make_shared<QGraphicsTextItem>();
   addItem(m_percentageText.get());
   m_percentageText->setDefaultTextColor(QColor(255,255,255));
   m_percentageText->setPlainText(QString::number(m_percentage));
   m_percentageText->setPos(0,0);
}

void GameScene::updateLinksBtwPlanets(Planet* currentItem)
{
   m_currentItem = currentItem;
   invalidate();
}

void GameScene::drawBackground(QPainter *painter, const QRectF &rect)
{
   qDebug() << "GameScene::drawBackground" << GetCurrentThreadId();
   QGraphicsScene::drawBackground(painter, rect);
   if (!selectedItems().isEmpty() && m_currentItem)
   {
      QList<QGraphicsItem*> SelectedItems = selectedItems();

      QPointF currentPlanetCenter, targetPlanetCenter = m_currentItem->pos();
      foreach(QGraphicsItem* item, SelectedItems)
      {
         currentPlanetCenter = item->pos();
         painter->setPen(m_jointPen);
         painter->drawLine(currentPlanetCenter,targetPlanetCenter);
      }
   }
   
}

void GameScene::planetClicked( PlanetPtr item)
{
   qDebug() << "GameScene::planetClicked" << GetCurrentThreadId();
   qDebug() << "GameScene::planetClicked( QGraphicsObject* )";

   m_lastSelectedItem = item;
   invalidate();
}

void GameScene::launchShips()
{
   LARGE_INTEGER li;
   unsigned int countOfShipsOnSourcePlanet = 0;
   FlightInfoPtr flightInfoPtr = boost::make_shared<FlightInfo>();
   flightInfoPtr->SetDstPlanetID(m_lastSelectedItem->GetPlanetID());
   foreach (const PlanetPtr& planet, m_lastSelectedPlanets)
   {
      QueryPerformanceCounter(&li);
      countOfShipsOnSourcePlanet = planet->CountOfShips();
      if ((countOfShipsOnSourcePlanet * m_percentage) / 100 > 0)
      {
         flightInfoPtr->AddSrcPlanet(PlanetShipsCountPair(planet->GetPlanetID(), planet->CountOfShips() * m_percentage / 100.0));
         Ships* group = new Ships(shared_from_this(), li.QuadPart, planet, m_lastSelectedItem, m_playerID, m_percentage, true, true);
         group->start(QAbstractAnimation::DeleteWhenStopped);
         
      }
   }
   if (!flightInfoPtr->GetSrcPlanets().empty())
   {
      emit ShipsLaunched(flightInfoPtr);
   }
}

void GameScene::disconnectSignals()
{
   disconnect();
   dumpObjectInfo();
}

void GameScene::mouseReleaseEvent( QGraphicsSceneMouseEvent * event )
{
   //qDebug() << "GameScene::mouseReleaseEvent";
   try
   {
      QGraphicsScene::mouseReleaseEvent(event);
      
      bool playerPlanetsSelected = isCurrentPlayerPlanetsSelected();

      if (playerPlanetsSelected)
      {
         m_lastSelectedPlanets.clear();
         getActuallySelectedPlanets(m_lastSelectedPlanets, playersEqual);
      }
      else if (selectedItems().count() == 1)
      {
         PlanetPtr planetPtr;
         foreach (const PlanetsPair& planet, *m_planets)
         {
            planetPtr = planet.second;
            if (planetPtr->isSelected())
            {
               m_lastSelectedItem = planetPtr;
               break;
            }
         
         }
         launchShips();
         m_lastSelectedItem->setSelected(false);
         selectItems(m_lastSelectedPlanets, true);
      }
      else
      {
         m_lastSelectedPlanets.clear();
         clearSelection();
      }
   }
   catch (const std::exception& e)
   {
      m_lastSelectedPlanets.clear();
      m_lastSelectedItem.reset();
      QMessageBox::information(NULL,"Error", e.what(), QMessageBox::Ok);
   }
}

template<typename Predicate>
void GameScene::getActuallySelectedPlanets(PlanetsVector& items, Predicate pred)
{
   boost::shared_ptr<Planet> currPlanet;

   foreach (const PlanetsPair& planet, *m_planets)
   {
      currPlanet = planet.second;
      if (planet.second->isSelected() && pred(currPlanet->GetPlanetOwnerID(), m_playerID) )
      {
         items.push_back(currPlanet);
      }
      else
      {
         planet.second->setSelected(false);
      }
   }
}

void GameScene::selectItems( PlanetsVector& items, bool val )
{
   foreach (const PlanetPtr& currentPlanet, items)
   {
      currentPlanet->setSelected(val);
   }
}

bool GameScene::isCurrentPlayerPlanetsSelected() const
{
   boost::shared_ptr<Planet> currPlanet;
   foreach (const PlanetsPair& planet, *m_planets)
   {
      currPlanet = planet.second;
      if (currPlanet->isSelected() && currPlanet->GetPlanetOwnerID() == m_playerID)
      {
         return true;
      }
   }
   return false;
}

void GameScene::newShipsArrived(ShipPtr ship, const PlanetPtr destinationPlanet, const unsigned int countOfShips, const PlayerID playerID )
{
   const PlayerID playerIDOfDestinationPlanet = destinationPlanet->GetPlanetOwnerID();
   const unsigned int countOfShipsOnDestinationPlanet = destinationPlanet->CountOfShips();
   if (playerIDOfDestinationPlanet == playerID)
   {
      destinationPlanet->CountOfShips(countOfShipsOnDestinationPlanet + countOfShips);
   }
   else
   {
      const unsigned int newCountOfShips = countOfShipsOnDestinationPlanet >= countOfShips ? countOfShipsOnDestinationPlanet - countOfShips : countOfShips - countOfShipsOnDestinationPlanet;
      destinationPlanet->CountOfShips(newCountOfShips);
   }

   if (countOfShips > countOfShipsOnDestinationPlanet)
   {
      destinationPlanet->PlanetOwner(m_players->at(playerID));
   }

   destinationPlanet->update();
   removeItem(ship.get());

   if (ship->NotifyOnArrival())
   {

      ShipsArrivedInfoPtr flightInfoPtr = boost::make_shared<ShipsArrivedInfo>(destinationPlanet->GetPlanetID(), destinationPlanet->CountOfShips(), destinationPlanet->GetPlanetOwnerID());
      
      emit ShipsArrivedToPlanet(flightInfoPtr);
   }
}

void GameScene::wheelEvent( QGraphicsSceneWheelEvent *event )
{
   int delta = event->delta();
   int countOfRotations = delta / distanceInRotation;
   m_percentage += countOfRotations * percentageAddend;
   if (m_percentage > 100)
      m_percentage = 100;
   else if (m_percentage < 5)
      m_percentage = 5;
   m_percentageText->setPlainText(QString::number(m_percentage));
}

void GameScene::LaunchShips( const FlightInfoPtr flightInfoPtr )
{
   LARGE_INTEGER li;
   unsigned int countOfPlanetsOnSourcePlanet = 0;
   PlanetPtr dstPlanet = m_planets->at(flightInfoPtr->GetDstPlanetID());
   PlanetPtr currentSrcPlanet;
   const PlanetIDMap& planetIDMap = flightInfoPtr->GetSrcPlanets();
   foreach (const PlanetShipsCountPair& currentPlanet, planetIDMap)
   {
      QueryPerformanceCounter(&li);
      currentSrcPlanet = m_planets->at(currentPlanet.first);
      countOfPlanetsOnSourcePlanet = currentSrcPlanet->CountOfShips();
      if (countOfPlanetsOnSourcePlanet > 0)
      {
         Ships* group = new Ships(shared_from_this(), li.QuadPart, currentSrcPlanet, dstPlanet, currentSrcPlanet->GetPlanetOwnerID(), currentPlanet.second, false, false);
         group->start(QAbstractAnimation::DeleteWhenStopped);
      }
   }
}